#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

struct epoll_event_ctl
{
    struct epoll_event buf;
    
    struct epoll_event_ctl *next;
    struct epoll_event_ctl *prev;
};

int get_listen_tcp(char *);

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        perror("plread input port");
        return -1;
    }

    int tcp_fd = get_listen_tcp(argv[1]);

    int epoll_fd = epoll_create(1);
    if (epoll_fd < 0)
    {
        perror("epoll_fd fail");
        exit(-1);
    }

    struct epoll_event tcp_event;
    tcp_event.data.fd = tcp_fd;
    tcp_event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, tcp_fd, &tcp_event);

    struct epoll_event epoll_event_ctl[1000];
    int sock_fd;
    int con_fd;
    struct sockaddr client_addr;
    socklen_t len = sizeof(struct sockaddr_in);
    struct epoll_event con_event;
    char buf[1024];
    int number;
    while (1)
    {
        number = epoll_wait(epoll_fd, epoll_event_ctl, 1000, -1);
        if (number > 0)
        {
            for (int i = 0; i < number; i++)
            {
                sock_fd = epoll_event_ctl[i].data.fd;
                if (sock_fd == tcp_fd)
                {
                    con_fd = accept(tcp_fd, (struct sockaddr *)&client_addr, &len);
                    con_event.data.fd = con_fd;
                    con_event.events = EPOLLIN | EPOLLRDHUP | EPOLLET;

                    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, con_fd, &con_event);
                }
                else if (epoll_event_ctl[i].events & EPOLLIN)
                {
                    memset(buf, 0, 1024);
                    printf("%d\n",sock_fd);
                    read(sock_fd, buf, 1024);
                    printf("read is %s\n", buf);
                    sleep(1);
                }
                else if (epoll_event_ctl[i].events & EPOLLRDHUP)
                {
                    memset(&con_event, 0, sizeof(con_event));
                    printf("del: %d\n",sock_fd);
                    epoll_ctl(epoll_fd, EPOLL_CTL_DEL, sock_fd, 0);
                }
            }
        }
    }

    close(tcp_fd);
    return 0;
}

int get_listen_tcp(char *port)
{
    int tcp_fd;
    tcp_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (tcp_fd < 0)
    {
        perror("socket fail");
        exit(-1);
    }

    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(atoi(port));

    inet_pton(AF_INET, "0.0.0.0", &server_addr.sin_addr);
    socklen_t len = sizeof(struct sockaddr_in);

    int ret = bind(tcp_fd, (struct sockaddr *)&server_addr, len);
    if (ret < 0)
    {
        perror("bind fail");
        exit(-1);
    }

    int on = 1;
    setsockopt(tcp_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

    listen(tcp_fd, 20);

    return tcp_fd;
}
